/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_matrix.h                                                           *
 ****************************************************************************/

/**
 * @file elisa_matrix.h
 * @brief Classes for management of matrices.
 */

/**
 * @defgroup Utility Utility
 * @brief Utilities.
 */


#ifndef _ELISA_MATRIX_H
#define _ELISA_MATRIX_H

#include <iostream>
#include "elisa_defs.h"

NAMESPACE_ELISA
/**
 * @ingroup Utility
 * @class DenseMatrix
 * @brief Dense matrix
 */
template <class T>
class DenseMatrix {
public:

	typedef T Element;

	/// @name Constructors
	//@{
	DenseMatrix(int i, int j, const T & val);
	DenseMatrix(int i, int j);
	DenseMatrix(int i);
	DenseMatrix(const DenseMatrix & m);
	//@}

	/// Destructor
	~DenseMatrix()
	{
		delete[] _els;
	}


	/// Copy
	DenseMatrix & operator=(const DenseMatrix & m);


	/// @name Access to dimensions
	//@{
	int nRows() const
	{
		return _r;
	}
	int nColumns() const
	{
		return _c;
	}
	//@}


	/// @name Access to elements
	//@{
	T operator()(int i, int j) const
	{
		return _els[(i - 1) * _c + (j - 1)];
	}
	T & operator()(int i, int j)
	{
		return _els[(i - 1) * _c + (j - 1)];
	}


	/// Access to vector
	T operator()(int i) const
	{
		return _els[i - 1];
	}
	T & operator()(int i)
	{
		return _els[i - 1];
	}
	//@}


private:
	T *_els;   // vector of elements
	int _r;    // number of rows
	int _c;    // number of columns
	long _nb;  // number of elements
};

//--------------------------------------------------------------------------
// class DenseMatrix: implementation of members
//--------------------------------------------------------------------------

template <class T>
DenseMatrix<T>::DenseMatrix(int i,
                            int j,
                            const T & val)
{
	_r = i;
	_c = j;
	_els = new T[_nb = i * j];
	for (int n = 0; n < _nb; ++n) {
		_els[n] = val;
	}
}

template <class T>
DenseMatrix<T>::DenseMatrix(int i,
                            int j)
{
	_r = i;
	_c = j;
	_els = new T[_nb = i * j];
}

template <class T>
DenseMatrix<T>::DenseMatrix(int i)
{
	_r = _c = i;
	_els = new T[_nb = i * i];
}

template <class T>
DenseMatrix<T>::DenseMatrix(const DenseMatrix & m)
{
	_r = m._r;
	_c = m._c;
	_els = new T[_nb = _r * _c];
	memcpy(_els, m._els, _nb * sizeof(T));
}

template <class T>
DenseMatrix<T>&DenseMatrix<T>::operator=(const DenseMatrix<T> & m)
{
	if ((_r != m._r) || (_c != m._c)) {
		delete[] _els;
		_r = m._r;
		_c = m._c;
		_els = new T[_nb = _r * _c];
	}
	memcpy(_els, m._els, _nb * sizeof(T));
	return *this;
}

END_NAMESPACE_ELISA

template <class T>
std::ostream &
operator<<(std::ostream & os,
           const elisa::DenseMatrix<T> & m)
{
	for (int i = 1; i <= m.nRows(); ++i) {
		os << "( ";
		for (int j = 1; j <= m.nColumns(); ++j) {
			os << m(i, j);
			if (j < m.nColumns()) {
				os << " ; ";
			}
		}
		os << " )" << std::endl;
	}
	return os;
}

#endif
